package CSV;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;

public class Apriori {
	HashSet<String> wholeItemSet;
	HashMap<Integer, HashSet<String>> transactionSet;
	HashMap<ArrayList<String>, Integer> Answer;
	double minsup;

	public Apriori(HashSet<String> wholeItemSet, double minsup) {
		this.wholeItemSet = new HashSet<String>();
		this.wholeItemSet = wholeItemSet;
		this.transactionSet = new HashMap<Integer, HashSet<String>>();
		this.minsup = minsup;
		this.Answer = new HashMap<ArrayList<String>, Integer>();
	}

	public void SetTran(HashMap<Integer, HashSet<String>> trans) {
		this.transactionSet = trans;
	}

	@SuppressWarnings("unchecked")
	public HashMap<ArrayList<String>, Integer> AprioriAlgo() {
		HashMap<ArrayList<String>, Integer> L = new HashMap<ArrayList<String>, Integer>(); // is
																							// the
																							// L1
																							// in
																							// the
																							// algorithm

		HashMap<String, Integer> temp_hm = new HashMap<String, Integer>();
		Iterator<HashSet<String>> titer = this.transactionSet.values()
				.iterator();
		while (titer.hasNext()) {
			HashSet<String> t = new HashSet<String>();
			t = (HashSet<String>) titer.next();
			Iterator<String> Liter = this.wholeItemSet.iterator();
			while (Liter.hasNext()) {
				String item = (String) Liter.next();
				if (t.contains(item)) {
					if (!temp_hm.containsKey(item)) {
						temp_hm.put(item, 1);
					} else {
						int temp_value = (Integer) temp_hm.get(item) + 1;
						temp_hm.remove(item);
						temp_hm.put(item, temp_value);
					}
				}

			}
		}

		Iterator<String> temp_hm_iter = temp_hm.keySet().iterator();
		while (temp_hm_iter.hasNext()) {
			String item = (String) temp_hm_iter.next();
			if ((Integer) temp_hm.get(item) >= (this.minsup * this.transactionSet
					.size())) { // find the large 1 item sets
				ArrayList<String> tempsh = new ArrayList<String>();
				tempsh.add(item);
				L.put(tempsh, (Integer) temp_hm.get(item));
			}
		} // initialize to the set of large 1 item set

		while (!L.isEmpty()) {
			Iterator<ArrayList<String>> Liter = L.keySet().iterator();
			while (Liter.hasNext()) {
				ArrayList<String> element = Liter.next();
				this.Answer.put(element, L.get(element));
			}
			HashMap<ArrayList<String>, Integer> CandidateK = AprioriGen(L);
			HashMap<ArrayList<String>, Integer> CandidateKMirror = (HashMap) CandidateK
					.clone();
			Iterator<HashSet<String>> Titer = this.transactionSet.values()
					.iterator();
			while (Titer.hasNext()) {
				HashSet<String> t = new HashSet<String>();
				t = (HashSet<String>) Titer.next();
				Iterator<ArrayList<String>> Citer = CandidateK.keySet()
						.iterator(); // CandidateT =
				// subset(CandidateK,
				// t);
				// System.out.println("transaction "+t.toString());
				while (Citer.hasNext()) {
					ArrayList<String> c = new ArrayList<String>();
					c = Citer.next();
					// System.out.println(c.toString());
					if (t.containsAll(c)) {
						// System.out.println("---------------------");
						int count = (Integer) CandidateKMirror.get(c) + 1; // c.count
						CandidateKMirror.remove(c);
						CandidateKMirror.put(c, count);
					}
				}
			}
			CandidateK.clear();
			CandidateK = (HashMap<ArrayList<String>, Integer>) CandidateKMirror
					.clone();
			CandidateKMirror.clear();
			HashMap<ArrayList<String>, Integer> temp = new HashMap<ArrayList<String>, Integer>();
			Iterator<ArrayList<String>> Citer = CandidateK.keySet().iterator();
			while (Citer.hasNext()) {
				ArrayList<String> c = new ArrayList<String>();
				c = Citer.next();
				if ((Integer) CandidateK.get(c) >= (this.minsup * this.transactionSet
						.size())) {
					temp.put(c, (Integer) CandidateK.get(c));
				}
			}
			L.clear();
			L = (HashMap<ArrayList<String>, Integer>) temp.clone(); // Lk
			temp.clear();
		}
		return this.Answer;
	}

	@SuppressWarnings("unchecked")
	private HashMap<ArrayList<String>, Integer> AprioriGen(
			HashMap<ArrayList<String>, Integer> L) {
		HashMap<ArrayList<String>, Integer> Lk = new HashMap<ArrayList<String>, Integer>();
		Lk = (HashMap<ArrayList<String>, Integer>) L.clone();
		HashMap<ArrayList<String>, Integer> CandidateK = new HashMap<ArrayList<String>, Integer>();
		// join step
		Iterator<ArrayList<String>> Liter1 = L.keySet().iterator();
		while (Liter1.hasNext()) {
			ArrayList<String> p = new ArrayList<String>();
			p = Liter1.next();
			Iterator<ArrayList<String>> Liter2 = L.keySet().iterator();
			while (Liter2.hasNext()) {
				ArrayList<String> q = new ArrayList<String>();
				q = Liter2.next();
				int k = q.size();
				ArrayList<String> Temp = new ArrayList<String>();
				// Temp.addAll(p);
				// Temp.addAll(q);
				boolean flag = false;
				for (int m = 0; m < k - 1; m++) {
					if (!p.get(m).equals(q.get(m))) {
						flag = true;
						break;
					}
				}
				if (p.get(k-1).equals(q.get(k-1))){
					flag = true;
				}
				if (!flag) {
					for (int m = 0; m < k - 1; m++) {
						Temp.add(p.get(m));
					}
					if (p.get(k - 1).compareTo(q.get(k - 1)) < 0) {
						Temp.add(p.get(k - 1));
						Temp.add(q.get(k - 1));
					} else {
						Temp.add(q.get(k - 1));
						Temp.add(p.get(k - 1));
					}
					// System.out.println(k);
					// System.out.println(Temp.toString());
					if (!CandidateK.containsKey(Temp)) {
						CandidateK.put(Temp, 0);
					}
				}
			}
		}
		// prune step
		Iterator<ArrayList<String>> Citer = CandidateK.keySet().iterator(); // for
																			// all
																			// item
																			// sets
																			// c
																			// do
		HashMap<ArrayList<String>, Integer> CandidateKMirror = new HashMap<ArrayList<String>, Integer>();
		CandidateKMirror = (HashMap<ArrayList<String>, Integer>) CandidateK
				.clone();
		while (Citer.hasNext()) {
			ArrayList<String> c = new ArrayList<String>();
			c = Citer.next();
			// get the k item subset by remove one item from the k+1 item subset
			Iterator<String> itemiter = c.iterator();
			while (itemiter.hasNext()) {
				String item = (String) itemiter.next();
				ArrayList<String> temp = new ArrayList<String>();
				temp = (ArrayList<String>) c.clone();
				temp.remove(item);
				if (!Lk.keySet().contains(temp)) {
					CandidateKMirror.remove(c);
					break;
				}
			}
		}
		CandidateK.clear();
		CandidateK = CandidateKMirror;

		return CandidateK;
	}

}
